home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / video / fly8111-.000 / fly8111- / fly8 / show.c < prev    next >
C/C++ Source or Header  |  1979-12-31  |  13KB  |  574 lines

  1. /* -------------------------------- show.c ---------------------------------- */
  2.  
  3. /* This is part of the flight simulator 'fly8'.
  4.  * Author: Eyal Lebedinsky (eyal@ise.canberra.edu.au).
  5. */
  6.  
  7. /* A 3D graphics engine.
  8. */
  9.  
  10. #include "fly.h"
  11.  
  12.  
  13. #if 0
  14. /*
  15.  * This one tries a different projection. It produces a more uniform
  16.  * distortion in wide angle. The method is to project the world onto a sphere
  17.  * and then use the latitude/longitude as the x/y on the screen. Perspective
  18.  * projection shows objects larger on the edges that in the center, this one
  19.  * shows equal size objects (same angle of view) with equal size.
  20.  * The problem is that straight lines show as arcs!
  21. */
  22. #define PROJ(x,pr,z) \
  23.      (projtype ? fmul((pr)*2,ATAN((x),(z))) : muldiv((x),(pr),(z)))
  24. #else
  25. #define PROJ(x,pr,z)    muldiv((x),(pr),(z))
  26. #endif
  27.  
  28. #define PROJPT(x,y,z,org,pr) \
  29.     if (z) \
  30.         gr_move (org[X]+PROJ(x,pr[X],z), org[Y]-PROJ(y,pr[Y],z)); \
  31.     else \
  32.         gr_move (org[X], org[Y])
  33.  
  34. #define PROJMV(x,y,z,org,pr) \
  35.     if (z) \
  36.         gr_draw (org[X]+PROJ(x,pr[X],z), org[Y]-PROJ(y,pr[Y],z)); \
  37.     else \
  38.         gr_draw (org[X], org[Y])
  39.  
  40. #define GETALPHA(a,b)    (tt2 = B[Z]/2 + b/2 + (tt1 =  a/2 - A[Z]/2))
  41.  
  42. #define CLIP(a,b)    (a + 2*muldiv(b/2-a/2,tt1,tt2))
  43.  
  44. static VECT    NEAR V1 = {0}, NEAR A = {0}, NEAR B = {0};
  45. static int    NEAR SH[2] = {0};    /* viewport shift from eye, x and y */
  46. static int    NEAR PR[2] = {0};    /* perspective ratio */
  47. static int    NEAR ORG[2] = {0};    /* pixel origin */
  48. static VECT    NEAR R = {0};        /* translation vector */
  49. static MAT    NEAR TT = {{0}};    /* rotation matrix */
  50. static VERTEX    NEAR V[1] = {{{0}}};    /* vertex being shown */
  51.  
  52. LOCAL_FUNC int NEAR
  53. adj (void)
  54. {
  55.     register int    tt1, tt2, tt3;
  56.  
  57. /* A straight forward clipping routine. Clip againt the right, left
  58.  * top and bottom in order.
  59. */
  60.     if (V1[Z] < V1[Y]) {
  61.         GETALPHA (A[Y], -B[Y]);
  62.         if (tt2  && (tt3 = CLIP (A[Z], B[Z])) > 0) {
  63.             V1[Y] = V1[Z] = tt3;
  64.             V1[X] = CLIP (A[X], B[X]);
  65.         }
  66.     }
  67.     if (V1[Z] < -V1[Y]) {
  68.         GETALPHA (-A[Y], B[Y]);
  69.         if (tt2  && (tt3 = CLIP (A[Z], B[Z])) > 0) {
  70.             V1[Y] = -(V1[Z] = tt3);
  71.             V1[X] = CLIP (A[X], B[X]);
  72.         }
  73.     }
  74.  
  75.     if (V1[Z] < V1[X]) {
  76.         GETALPHA (A[X], -B[X]);
  77.         if (tt2  && (tt3 = CLIP (A[Z], B[Z])) > 0) {
  78.             V1[X] = V1[Z] = tt3;
  79.             V1[Y] = CLIP (A[Y], B[Y]);
  80.         }
  81.     }
  82.     if (V1[Z] < -V1[X]) {
  83.         GETALPHA (-A[X], B[X]);
  84.         if (tt2  && (tt3 = CLIP (A[Z], B[Z])) > 0) {
  85.             V1[X] = -(V1[Z] = tt3);
  86.             V1[Y] = CLIP (A[Y], B[Y]);
  87.         }
  88.     }
  89.  
  90.     if (V1[Z] < V1[X] || V1[Z] < -V1[X] ||
  91.         V1[Z] < V1[Y] || V1[Z] < -V1[Y])
  92.         return (1);
  93.     return (0);
  94. }
  95.  
  96. LOCAL_FUNC void NEAR FASTCALL
  97. show_line ()
  98. {
  99.     register int    xxxx;
  100.     static int    yyyy, prev = 0;
  101.  
  102. /* V->V is in object coordinates
  103. */
  104.     VMmul (A, V->V, TT);        /* rotate */
  105.  
  106. /* A is in viewer's coordinates, but at origin.
  107. */
  108.     Vinc (A, R);            /* translate (R already rotated) */
  109.  
  110. /* A is now in viewer coordinates, in position.
  111.  *
  112.  * We now swap y and z in the viewer's coordinate system:
  113.  * x was 'right' (still is)
  114.  * y was 'forward' (now is 'up', so the screen is x-y)
  115.  * z was 'up' (now is 'forward', perpendicular to the screen)
  116. */
  117.     xxxx = A[Z];    /* xxxx used as temp */
  118.     A[Z] = A[Y];
  119.     A[Y] = xxxx;
  120.  
  121. /* shift the x and y to compensate for viewport offset.
  122.  * SH is in viewers coordinates.
  123.  * This is not properly done. SH[] is always zero for now.
  124.  * Actualy, the "dynamic" scaling for truncation control makes this
  125.  * shift WRONG!
  126. */
  127.     A[X] -= SH[X];
  128.     A[Y] -= SH[Y];
  129.  
  130. /* xxxx is clipping pattern:
  131.  *    0x01: x >  z (too far right)
  132.  *    0x02: x < -z (too far left)
  133.  *    0x04: y >  z (too far up)
  134.  *    0x08: y < -z (too far down)
  135.  *    0x10: z <  0 (behind)
  136. */
  137.      xxxx = 0;
  138.     if (A[X] > A[Z])
  139.         xxxx |= 0x01;
  140.     if (A[X] < -A[Z])
  141.         xxxx |= 0x02;
  142.     if (A[Y] > A[Z])
  143.         xxxx |= 0x04;
  144.     if (A[Y] < -A[Z])
  145.         xxxx |= 0x08;
  146.     if (A[Z] < 0)
  147.         xxxx |= 0x10;
  148.  
  149.     Vcopy (V1, A);
  150.  
  151. /* Use the bit pattern of the current point and the previous one to
  152.  * attempt fast rejects/accepts and avoid un-necessary clipping.
  153.  *
  154.  * 'V_MOVE' means the segment into this point is not to be drawn.
  155.  *
  156.  * 'prev' is true if the last point was not drawn (which means the
  157.  * graphics device is not at the current position).
  158.  *
  159.  * adj() clips one endpoint.
  160.  *
  161.  * PROJMV() projects a point and draw a line to it.
  162.  *
  163.  * PROJPT() projcts a point and issues command to move there without
  164.  * drawing (just a re-positioning).
  165. */
  166.     if (V_MOVE == V->flags || V_DUP == V->flags)
  167.         goto noline;
  168.  
  169.     ++STATS_CLIPCOUNT;
  170.  
  171.     if (xxxx == yyyy) {
  172.         if (xxxx)
  173.             {++STATS_CLIPOUT;    goto reject;}
  174.         else
  175.             goto same;
  176.     }
  177.     if (xxxx & yyyy)
  178.         {++STATS_CLIPOUT;    goto reject;}
  179.     if (0 == prev)
  180.         {++STATS_CLIPINOUT;     goto newout;}
  181.     if (0 == yyyy)
  182.         goto oldin;
  183.     if (0 == xxxx)
  184.         goto newin;
  185.  
  186. /* The case is undecided so one clipping is attempted. If it fails
  187.  * then we reject this segment. This is the only time a failure is
  188.  * expected. In the other cases, a failure of adj() means that an
  189.  * unexpected problem prevented it from working - usualy a result
  190.  * of lost resolution due to truncation.
  191. */
  192.  
  193.     if (adj ())        /* a trial clipping */
  194.         {++STATS_CLIPOUTHARD;     goto noline;}
  195.     PROJPT (V1[X], V1[Y], V1[Z], ORG, PR);
  196.     Vcopy (V1, B);
  197. newout:
  198.     if (adj ())        /* should not fail */
  199.         {++STATS_CLIPOUTFAILED;     goto noline;}
  200.     ++STATS_CLIPINHARD;
  201.     PROJMV (V1[X], V1[Y], V1[Z], ORG, PR);
  202. reject:
  203. noline:
  204.     prev = 1;
  205.     goto ret;
  206.  
  207. oldin:
  208.     PROJPT (B[X], B[Y], B[Z], ORG, PR);
  209.     ++STATS_CLIPINOUT;        goto newout;
  210. newin:
  211.     ++STATS_CLIPINOUT;
  212.     Vcopy (V1, B);
  213.  
  214.     if (adj ())        /* should not fail */
  215.         goto noline;
  216.     PROJPT (V1[X], V1[Y], V1[Z], ORG, PR);
  217.     goto newin1;
  218. same:
  219.     ++STATS_CLIPIN;
  220.     if (prev) {
  221.         PROJPT (B[X], B[Y], B[Z], ORG, PR);
  222.     }
  223. newin1:
  224.     PROJMV (A[X], A[Y], A[Z], ORG, PR);
  225.     prev = 0;
  226. ret:
  227.     yyyy = xxxx;
  228.     Vcopy (B, A);
  229. }
  230. #undef PROJ
  231. #undef PROJPT
  232. #undef PROJMV
  233. #undef GETALPHA
  234. #undef CLIP
  235.  
  236. static VERTEX FAR shape_dot[] = {
  237.     {{0, 0, 0}, V_MOVE},
  238.     {{0, 0, 0}, V_DRAW},
  239.     {{0, 0, 0}, V_EOF}
  240. };
  241.  
  242. LOCAL_FUNC void NEAR
  243. show_object (int mode, OBJECT *obj , MAT VT, LVECT VR, int frame,
  244.     long minextent, LVECT OR, VECT RR)
  245. {
  246.     register VERTEX    *v;
  247.     VECT        P;
  248.     LVECT        LP;
  249.     long        l, dist, extent;
  250.     int        scale, too_far, too_near, obj_size, depth;
  251.     int        t, b;
  252.     int        color;
  253.  
  254. /* Get vector from viewr to object.
  255. */
  256.     if (1 == mode)
  257.         Vsub (LP, OR, VR);
  258.     else
  259.         Vsub (LP, obj->R, VR);
  260.  
  261. /* If the object is too far, show only a dot. This enables the
  262.  * use of 16-bit arithmetic in a 32-bit world. If it is much further
  263.  * then don't show it at all.
  264. */
  265.     dist = labs (LP[X]);
  266.     if ((l = labs (LP[Y])) > dist)
  267.         dist = l;
  268.     if ((l = labs (LP[Z])) > dist)
  269.         dist = l;
  270.  
  271.     if (0 == mode) {
  272.         if (dist/4/minextent > (long)SH(obj)->extent)
  273.             return;
  274.         obj_size = SH(obj)->extent;
  275.         extent = dist + obj_size*(long)VONE;
  276.     } else {
  277.         obj_size = 1;
  278.         extent = dist;
  279.     }
  280.  
  281.     too_near = too_far = 0;
  282.     if (extent == 0) {
  283.         if (0 == mode)
  284.             return;
  285.         P[X] = LP[X];
  286.         P[Y] = LP[Y];
  287.         P[Z] = LP[Z];
  288.         scale = 1;
  289.     } else if (extent > 0x7fffL*VONE) {
  290.  
  291. /* Bring far objects nearer.
  292. */
  293.         too_far = 1;
  294.         scale = (int)(extent / (0x7fff/2));
  295.         scale = (scale/VONE)*VONE;
  296.         P[X] = (int)(LP[X] / scale);
  297.         P[Y] = (int)(LP[Y] / scale);
  298.         P[Z] = (int)(LP[Z] / scale);
  299.         scale /= VONE;
  300.         obj_size /= scale;
  301.     } else if (extent <= 0x7fff/4) {
  302.  
  303. /* Reduce truncation errors: push near points away.
  304. */
  305.         too_near = 1;
  306.         scale = (int)((0x7fff/2) / extent);
  307.         P[X] = ((int)LP[X]) * scale;
  308.         P[Y] = ((int)LP[Y]) * scale;
  309.         P[Z] = ((int)LP[Z]) * scale;
  310.         scale *= VONE;
  311.         obj_size *= scale;
  312.     } else if (extent <= 0x7fffL*VONE/4) {
  313.  
  314. /* Reduce truncation errors: push near points away.
  315. */
  316.         too_near = 1;
  317.         scale = (int)((0x7fffL*VONE/2) / extent);
  318.         P[X] = (int)((LP[X] * scale) / VONE);
  319.         P[Y] = (int)((LP[Y] * scale) / VONE);
  320.         P[Z] = (int)((LP[Z] * scale) / VONE);
  321.         obj_size *= scale;
  322.     } else {
  323.  
  324. /* Shift out the fraction and move to 16-bits.
  325. */
  326.         P[X] = (int)vuscale (LP[X]);
  327.         P[Y] = (int)vuscale (LP[Y]);
  328.         P[Z] = (int)vuscale (LP[Z]);
  329.         scale = 1;
  330.     }
  331.  
  332. /* Rotate to viewer's orientation.
  333. */
  334.     if (1 == mode) {
  335.         VMmul (RR, P, VT);
  336.         return;
  337.     }
  338.  
  339.     VMmul (R, P, VT);    /* object's origin in viewer coordinates */
  340.  
  341. /* Rough check for object out of view (trivial reject).
  342. */
  343.     if (R[Y] <= -obj_size)        /* all behind */
  344.         return;
  345.     depth = R[Y]/2 + obj_size;    /* avoid truncation */
  346.     if (iabs(R[X]/2) > (Uint)depth || iabs(R[Z]/2) > (Uint)depth)
  347.         return;
  348.  
  349. /* Post conatenate Viewer's transposed matrix to the Object's.
  350. */
  351.     VMmul (TT[0], obj->T[0], VT);    /* Mmul (TT, obj->T, VT);*/
  352.     VMmul (TT[1], obj->T[1], VT);
  353.     VMmul (TT[2], obj->T[2], VT);
  354.  
  355. /* Far objects shown as one dot.
  356. */
  357.     if (dist/minextent > (long)SH(obj)->extent)
  358.         v = shape_dot;
  359.     else
  360.         v = SH(obj)->v;
  361.  
  362. /* Set object color
  363. */
  364.     if (dist*2/minextent > (long)SH(obj)->extent)
  365.         color = ST_FAINT;    /* farther than dot/2 */
  366.     else if (dist*4/minextent > (long)SH(obj)->extent)
  367.         color = ST_DULL;    /* farther than dot/4 */
  368.     else
  369.         color = obj->color;
  370.     gr_color (color);
  371.  
  372. /* Show each line segment in turn.
  373. */
  374.     if (SH(obj)->flags & SH_FINE) {
  375.         if (too_near) {
  376.             t = scale;
  377.             b = VONE;
  378.         } else if (too_far) {
  379.             t = 1;
  380.             b = scale * VONE;
  381.         } else {
  382.             t = 1;
  383.             b = VONE;
  384.         }
  385.     } else {
  386.         if (too_near) {
  387.             t = scale;
  388.             b = 1;
  389.         } else if (too_far) {
  390.             t = 1;
  391.             b = scale;
  392.         } else {
  393.             t = 1;
  394.             b = 1;
  395.         }
  396.     }
  397.  
  398.     for (; v->flags != V_EOF; ++v) {
  399. #if 0
  400.         Vmuldiv (V->V, v->V, t, b);
  401. #else
  402.         if (1 == t) {
  403.             if (1 == b)
  404.                 Vcopy (V->V, v->V);
  405.             else {
  406.                 V->V[X] = v->V[X] / b;
  407.                 V->V[Y] = v->V[Y] / b;
  408.                 V->V[Z] = v->V[Z] / b;
  409.             }
  410.         } else if (1 == b) {
  411.             V->V[X] = v->V[X] * t;
  412.             V->V[Y] = v->V[Y] * t;
  413.             V->V[Z] = v->V[Z] * t;
  414.         } else {
  415.             V->V[X] = muldiv (v->V[X], t, b);
  416.             V->V[Y] = muldiv (v->V[Y], t, b);
  417.             V->V[Z] = muldiv (v->V[Z], t, b);
  418.         }
  419. #endif
  420.         V->flags = v->flags;
  421.         show_line ();
  422.     }
  423. }
  424.  
  425. #define TSCALE    FCON(0.57735)    /* sqrt(1/3): cube diagonal to edge ratio */
  426.  
  427. /* mode:
  428.  * 0 show world
  429.  * 1 transform OR into RR
  430. */
  431. extern void FAR
  432. objects_show (int mode, VIEW *view, OBJECT *pov, int frame, LVECT OR, VECT RR)
  433. {
  434.     register int    i;
  435.     register OBJECT    *p;
  436.     MAT        VT;        /* rotates world to viewer */
  437.     LVECT        R;        /* eye position */
  438.     VECT        SC;        /* scaling */
  439.     VECT        E, EYE;      /* relative eye shift */
  440.     int        j;
  441.     int        l, t;
  442.     long        minextent;    /* minimum extent ratio to show */
  443.  
  444.     if (1 != mode) {
  445.         STATS_TCLIPOUT       += STATS_CLIPOUT;
  446.         STATS_TCLIPIN        += STATS_CLIPIN;
  447.         STATS_TCLIPINOUT     += STATS_CLIPINOUT;
  448.         STATS_TCLIPOUTHARD   += STATS_CLIPOUTHARD;
  449.         STATS_TCLIPOUTFAILED += STATS_CLIPOUTFAILED;
  450.         STATS_TCLIPINHARD    += STATS_CLIPINHARD;
  451.         STATS_TCLIPCOUNT     += STATS_CLIPCOUNT;
  452.         STATS_CLIPOUT         = 0;
  453.         STATS_CLIPIN          = 0;
  454.         STATS_CLIPINOUT       = 0;
  455.         STATS_CLIPOUTHARD     = 0;
  456.         STATS_CLIPOUTFAILED   = 0;
  457.         STATS_CLIPINHARD      = 0;
  458.         STATS_CLIPCOUNT       = 0;
  459.         Tm->Interval (TMR_START, 0L);
  460.     }
  461.  
  462. /* This is the entry point of this module.
  463.  *
  464.  * Adjust for eye distance and viewport size so that after total
  465.  * scaling there is no overflow. TSCALE is sqrt(1/3) and is the
  466.  * minimal scaling needed due to the 3D rotation. The rest is a
  467.  * distortion that accounts for the pictures aspect ratio; later,
  468.  * the program works in a square (45 degrees) clipping area.
  469. */
  470.     l = VP->z;                /* get minimum */
  471.     if (l > VP->maxx)
  472.         l = VP->maxx;
  473.     if (l > VP->maxy)
  474.         l = VP->maxy;
  475.     SC[X] = muldiv (TSCALE, l, VP->maxx);    /* never divide by zero!!! */
  476.     SC[Y] = muldiv (TSCALE, l, VP->maxy);
  477.     SC[Z] = muldiv (TSCALE, l, VP->z);
  478.  
  479. /* Adjust for viewer's offset to the viewport.
  480.  * (not quite right)
  481. */
  482.     SH[X] = fmul (VP->x, SC[X]);
  483.     SH[Y] = fmul (VP->y, SC[Y]);
  484.  
  485. /* Get 2D display area parameters.
  486. */
  487.     get_area (view, ORG+X, ORG+Y, PR+X, PR+Y);
  488.  
  489. /* Swap y and z when changing to viewer coordinates.
  490. */
  491.     t = SC[Y];
  492.     SC[Y] = SC[Z];
  493.     SC[Z] = t;
  494.  
  495. /* a mirror has left-right swapped.
  496. */
  497.     if (VP->flags & VF_MIRROR)
  498.         PR[X] = -PR[X];
  499.  
  500. /* Transpose viewer orientation matrix.
  501.  * The object's T maps from the object to the world and for
  502.  * the viewer we need the reverse mapping.
  503. */
  504.     Mcopy (VT, pov->T);
  505.     Mxpose (VT);
  506.  
  507. /* Rotate for viewer's gaze direction (and stereo cross-eye).
  508. */
  509.     if (VP->rotz)
  510.         Mrotz (VT, VP->rotz);
  511.     if (VP->rotx)
  512.         Mrotx (VT, VP->rotx);
  513.     if (VP->roty)
  514.         Mroty (VT, VP->roty);
  515.  
  516. /* Now do the scaling.
  517. */
  518.     for (i = 0; i < 3; ++i)        /* scale */
  519.         for (j = 0; j < 3; ++j)
  520.             VT[j][i] = fmul (VT[j][i], SC[i]);
  521.  
  522. /* Find eye position.
  523. */
  524.     EYE[X] = VP->eyex + VP->shift / VONE;
  525.     EYE[Y] = VP->eyey;
  526.     EYE[Z] = VP->eyez;
  527.     VMmul (E, EYE, pov->T);
  528.     Vadd (R, pov->R, E);
  529.  
  530. /* Calculate maximum distance for showing detail.
  531. */
  532. #if 1
  533.     minextent = VP->z * (long)VS->sizex / VP->maxx * VONE;
  534. #else
  535.     minextent = VP->z * (long)VS->sizex / VP->maxx * (VONE/2);
  536. #endif
  537.     if (minextent < 1)
  538.         minextent = 1;
  539.  
  540. /* If only object position requested, get it and quit.
  541. */
  542.     if (1 == mode) {
  543.         show_object (1, 0, VT, R, frame, minextent, OR, RR);
  544.         return;
  545.     }
  546.  
  547. /* Now show each object in turn.
  548. */
  549.     for (i = 0, p = CL; p; p = p->next) {
  550.         if (p->flags & F_VISIBLE) {
  551.             show_object (0, p, VT, R, frame, minextent, 0, 0);
  552.             if (!i--) {
  553.                 i = 20;
  554.                 sys_poll (6);        /* poll frequently */
  555.             }
  556.         }
  557.     }
  558.  
  559.     for (p = CO; p; p = p->next) {
  560.         if (p == pov)            /* don't show viewer */
  561.             continue;
  562.         if (p->flags & F_VISIBLE) {
  563.             show_object (0, p, VT, R, frame, minextent, 0, 0);
  564.             if (!i--) {
  565.                 i = 20;
  566.                 sys_poll (7);        /* poll frequently */
  567.             }
  568.         }
  569.     }
  570.     STATS_TIME3D += Tm->Interval (TMR_STOP, 10000L);
  571. }
  572.  
  573. #undef TSCALE
  574.